"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const PENDING = 'PENDING';
const START = 'START';
const FULFILLED = 'FULFILLED';
const SUCCESS = 'SUCCESS';
const REJECTED = 'REJECTED';
function getFetchActionType(type, status) {
    return `[${type}]_${status}`;
}
exports.getFetchActionType = getFetchActionType;
const ONE_PAGE_COUNT = 10;
const headers = new Headers();
headers.set('Content-Type', 'application/json');
let generateUUID = () => Date.now();
function setGenerateUUID(fun) {
    generateUUID = fun;
}
exports.setGenerateUUID = setGenerateUUID;
const payloadKeyFunArray = [];
function setPayloadKeyFun(key, fun) {
    const index = payloadKeyFunArray.findIndex(v => v.key == key);
    if (index >= 0) {
        payloadKeyFunArray.splice(index, 1);
    }
    payloadKeyFunArray.push({ key, fun });
}
exports.setPayloadKeyFun = setPayloadKeyFun;
const postKeyFunArray = [];
function setPostKeyFun(key, fun) {
    const index = postKeyFunArray.findIndex(v => v.key == key);
    if (index >= 0) {
        postKeyFunArray.splice(index, 1);
    }
    postKeyFunArray.push({ key, fun });
}
exports.setPostKeyFun = setPostKeyFun;
function createFetchPromiseMiddleware() {
    return (res) => (next) => (action) => {
        const { type, payload } = action;
        let meta = action.meta ? action.meta : {};
        if (!needFetch(action) || !payload) {
            return next(action);
        }
        const UUID = action.UUID ? action.UUID : generateUUID();
        const otherPayload = {};
        payloadKeyFunArray.forEach(v => {
            otherPayload[v.key] = v.fun(res.getState());
        });
        if (!otherPayload.url) {
            return next(action);
        }
        let page = 0;
        const getAction = (newPayload, result, status) => ({
            ignoreFetchPromise: true,
            type: getFetchActionType(type, status),
            payload: Object.assign({}, payload, newPayload, otherPayload),
            meta: Object.assign({}, meta, (page > 0 ? { page } : {})),
            UUID,
            result,
        });
        const pendingAction = getAction({}, null, PENDING);
        next(pendingAction);
        let userCancel = false;
        if (pendingAction.payload && pendingAction.payload.cancelFetch) {
            userCancel = pendingAction.payload.cancelFetch;
        }
        const info = getFetchInfo(payload.fetchInfoKey ? payload.fetchInfoKey : payload.fetch, res.getState());
        let promise = null;
        if (info.canFetch && !userCancel) {
            const otherP = {};
            postKeyFunArray.forEach(v => {
                otherP[v.key] = v.fun(res.getState());
            });
            let body = '';
            if (payload.paging) {
                page = info.page;
                body = generatePostData(Object.assign({}, meta, otherP, { page }));
            }
            else {
                body = generatePostData(Object.assign({}, meta, otherP));
            }
            next(getAction({ body }, null, START));
            promise = new Promise((resolve, reject) => {
                fetch(otherPayload.url + payload.fetch, {
                    method: 'POST',
                    body,
                    headers,
                })
                    .then((response) => {
                    if (response.status == 200) {
                        response.json()
                            .then((data) => {
                            resolve(data);
                        })
                            .catch((reason) => {
                            reject({ reason, flag: true, html: response });
                        });
                    }
                    else {
                        response.text()
                            .then((text) => {
                            reject({ reason: response.status, flag: true, html: text });
                        }).catch(() => {
                            reject({ reason: response.status, flag: true, html: response });
                        });
                    }
                })
                    .catch((reason) => {
                    reject({ reason, flag: true });
                });
            });
        }
        else {
            let reason = info.reason;
            if (userCancel && pendingAction.payload) {
                reason = pendingAction.payload.reason ? pendingAction.payload.reason : '在PENDING阶段手动取消';
            }
            promise = new Promise((resolve, reject) => {
                reject({ reason, flag: false, cancelFetch: userCancel });
            });
        }
        const promiseValue = promise
            .then((data) => {
            const { no, d, m } = data;
            if (no == 200) {
                return res.dispatch(getAction({}, { no, data: d }, SUCCESS));
            }
            else {
                return res.dispatch(getAction({}, { no, err: m }, FULFILLED));
            }
        })
            .catch((reason) => {
            return res.dispatch(getAction({ reason: reason.reason, resetPending: reason.flag, cancelFetch: reason.cancelFetch, html: reason.html }, null, REJECTED));
        });
        return promiseValue;
    };
}
exports.createFetchPromiseMiddleware = createFetchPromiseMiddleware;
function needFetch(action) {
    if (action.payload && (!action.ignoreFetchPromise)) {
        if (action.payload.fetch) {
            return true;
        }
    }
    return false;
}
function generatePostData(value) {
    // const keys = Object.keys(value);
    // return keys.map((key) => {
    //     let tmp = value[key];
    //     return key + '=' + tmp;
    // }).join('&');
    return JSON.stringify(value);
}
function getLength(value) {
    if (null == value) {
        return 0;
    }
    else if (Array.isArray(value)) {
        return value.length;
    }
    else if (typeof value === 'object') {
        return Object.keys(value).length;
    }
    return 0;
}
const FETCH_ACTIONS_HANDLER = {
    [PENDING]: (state, action) => {
        if (!action.payload) {
            return state;
        }
        const key = action.payload.fetchInfoKey ? action.payload.fetchInfoKey : action.payload.fetch;
        const info = state[key] ? Object.assign({}, state[key]) : action.payload.paging
            ? { canFetch: false, pending: false, page: 1, nextPage: true, isEmpty: false }
            : { canFetch: false, pending: false };
        if (action.payload.mandatory) {
            info.pending = false;
            if (action.payload.paging) {
                info.page = 1;
                info.nextPage = true;
                info.isEmpty = false;
                if (action.meta && action.meta.page) {
                    info.page = action.meta.page;
                }
            }
        }
        if (info.pending) {
            info.canFetch = false;
            info.reason = '上一个请求未完成';
        }
        else if (action.payload.paging && !info.nextPage) {
            info.canFetch = false;
            info.reason = '列表页数已经到最大了';
        }
        else {
            info.canFetch = true;
        }
        return Object.assign({}, state, { [key]: info });
    },
    [START]: (state, action) => {
        if (action.payload) {
            const key = action.payload.fetchInfoKey ? action.payload.fetchInfoKey : action.payload.fetch;
            const info = state[key] ? Object.assign({}, state[key]) : null;
            if (info) {
                info.pending = true;
                return Object.assign({}, state, { [key]: info });
            }
        }
        return state;
    },
    [REJECTED]: (state, action) => {
        if (action.payload) {
            if (action.payload.resetPending) {
                const key = action.payload.fetchInfoKey ? action.payload.fetchInfoKey : action.payload.fetch;
                const info = state[key] ? Object.assign({}, state[key]) : null;
                if (info) {
                    info.pending = false;
                    info.serverError = action.payload.reason ? action.payload.reason : '';
                    return Object.assign({}, state, { [key]: info });
                }
            }
        }
        return state;
    },
    [FULFILLED]: (state, action) => {
        if (action.payload) {
            const key = action.payload.fetchInfoKey ? action.payload.fetchInfoKey : action.payload.fetch;
            const info = state[key] ? Object.assign({}, state[key]) : null;
            if (info) {
                info.pending = false;
                if (action.result) {
                    info.serverError = action.result.no + ':' + action.result.err;
                }
                return Object.assign({}, state, { [key]: info });
            }
        }
        return state;
    },
    [SUCCESS]: (state, action) => {
        if (action.payload) {
            const key = action.payload.fetchInfoKey ? action.payload.fetchInfoKey : action.payload.fetch;
            const info = state[key] ? Object.assign({}, state[key]) : null;
            if (info) {
                info.pending = false;
                if (action.result && action.result.data) {
                    const { data } = action.result;
                    if (action.payload.paging) {
                        const pageInfo = info;
                        const len = action.payload.pageListData ? getLength(data[action.payload.pageListData]) : getLength(data);
                        pageInfo.nextPage = len >= ONE_PAGE_COUNT;
                        if (pageInfo.page == 1) {
                            pageInfo.isEmpty = len == 0;
                        }
                        pageInfo.page++;
                    }
                }
                return Object.assign({}, state, { [key]: info });
            }
        }
        return state;
    },
};
function fetchReducer(state = {}, action) {
    let handler = null;
    if (action.payload) {
        if (action.payload.fetch) {
            if (action.type[0] == '[' && (action.type.indexOf(']_' + PENDING) > 0)) {
                handler = FETCH_ACTIONS_HANDLER[PENDING];
            }
            else if (action.type[0] == '[' && (action.type.indexOf(']_' + START) > 0)) {
                handler = FETCH_ACTIONS_HANDLER[START];
            }
            else if (action.type[0] == '[' && (action.type.indexOf(']_' + REJECTED) > 0)) {
                handler = FETCH_ACTIONS_HANDLER[REJECTED];
            }
            else if (action.type[0] == '[' && (action.type.indexOf(']_' + FULFILLED) > 0)) {
                handler = FETCH_ACTIONS_HANDLER[FULFILLED];
            }
            else if (action.type[0] == '[' && (action.type.indexOf(']_' + SUCCESS) > 0)) {
                handler = FETCH_ACTIONS_HANDLER[SUCCESS];
            }
        }
    }
    // else if (action.type == Logout) {
    //     return {};
    // }
    return handler ? handler(state, action) : state;
}
exports.fetchReducer = fetchReducer;
exports.fetchSelector = (state) => state.fetch;
function getFetchInfo(action, state) {
    const fetchData = exports.fetchSelector(state);
    return fetchData[action] ? fetchData[action] : null;
}
exports.getFetchInfo = getFetchInfo;
